const qs = function (arg1, arg2) {
  if (typeof arg1 === "object") {
    return arg1.querySelector(arg2);
  } else if (typeof arg1 === "string") {
    return document.querySelector(arg1);
  } else {
    return null;
  }
};

const qsa = function (arg1, arg2) {
  if (typeof arg1 === "object") {
    return arg1.querySelectorAll(arg2);
  } else if (typeof arg1 === "string") {
    return document.querySelectorAll(arg1);
  } else {
    return null;
  }
};

const $on = function (target, type, callback, useCapture) {
  target.addEventListener(type, callback, !!useCapture);
};

const $delegated = function (target, selector, type, handler) {
  let dispatchEvent = (event) => {
    let targetElement = event.target;
    let potentialElements = qsa(target, selector);
    let hasMatch =
      Array.prototype.indexOf.call(potentialElements, targetElement) >= 0;

    if (hasMatch) {
      handler.call(targetElement, event);
    }
  };
  let useCapture = type === "blur" || type === "focus";
  $on(target, type, dispatchEvent, useCapture);
};

const attachEvent = function (target, selector, type, handler) {
  let dispatchEvent = (event) => {
    let targetElement = event.target;
    let potentialElements = qsa(target, selector);
    let hasMatch =
      Array.prototype.indexOf.call(potentialElements, targetElement) >= 0;

    if (hasMatch) {
      handler.call(targetElement, event, targetElement);
    } else {
      for (let node = targetElement; node !== target; node = node.parentNode) {
        hasMatch = Array.prototype.indexOf.call(potentialElements, node) >= 0;
        if (hasMatch) {
          handler.call(node, event, node);
          break;
        }
      }
    }
  };
  let useCapture = type === "blur" || type === "focus";
  $on(target, type, dispatchEvent, useCapture);
};
